﻿using System;
using System.Collections.Generic;
using Db4objects.Db4o;
using Db4objects.Db4o.Ext;
using DonNicky.Db;
using DonNicky.Db.Db4o.Config.Attributes;

namespace DonNicky.Db.Db4o
{
    [TransparentPersisted]
    public abstract class Db4oTPEntity : IDeletable, IObjectCallbacks
    {
        [Transient]
        internal bool Purging = false;
        private IList<Db4oTPChildEntity> _deletedChildren = new System.Collections.Generic.List<Db4oTPChildEntity>();
        private int _fake;
        private DateTime? _deletionTime = null;
        private bool _deleted = false;

        public class List<T> : IList<T>
        {
            private IList<T> _list = new System.Collections.Generic.List<T>();
            private Db4oTPEntity _parent;

            public List(Db4oTPEntity parent) { _parent = parent; }

            #region IList<T> Members

            public int IndexOf(T item) { return _list.IndexOf(item); }
            public void Insert(int index, T item) { _list.Insert(index, item); _parent.ForcedUpdate(); }
            public void RemoveAt(int index) { _list.RemoveAt(index); if (!_parent.Purging) _parent.ForcedUpdate(); }
            public T this[int index] { get { return _list[index]; } set { _list[index] = value; } }

            #endregion

            #region ICollection<T> Members

            public void Add(T item) { _list.Add(item); _parent.ForcedUpdate(); }
            public void Clear() { _list.Clear(); if (!_parent.Purging) _parent.ForcedUpdate(); }
            public bool Contains(T item) { return _list.Contains(item); }
            public void CopyTo(T[] array, int arrayIndex) { _list.CopyTo(array, arrayIndex); }
            public int Count { get { return _list.Count; } }
            public bool IsReadOnly { get { return _list.IsReadOnly; } }
            public bool Remove(T item) { if (!_parent.Purging) _parent.ForcedUpdate(); return _list.Remove(item); }

            #endregion

            #region IEnumerable<T> Members

            public IEnumerator<T> GetEnumerator() { return _list.GetEnumerator(); }

            #endregion

            #region IEnumerable Members

            System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return _list.GetEnumerator(); }

            #endregion
        }

        public class Dictionary<T, K> : IDictionary<T, K>
        {
            private IDictionary<T, K> _dict = new System.Collections.Generic.Dictionary<T, K>();
            private Db4oTPEntity _parent;

            public Dictionary(Db4oTPEntity parent) { _parent = parent; }

            #region IDictionary<T,K> Members

            public void Add(T key, K value) { _dict.Add(key, value); _parent.ForcedUpdate(); }
            public bool ContainsKey(T key) { return _dict.ContainsKey(key); }
            public ICollection<T> Keys { get { return _dict.Keys; } }
            public bool Remove(T key) { if(!_parent.Purging) _parent.ForcedUpdate(); return _dict.Remove(key); }
            public bool TryGetValue(T key, out K value) { return _dict.TryGetValue(key, out value); }
            public ICollection<K> Values { get { return _dict.Values; } }
            public K this[T key] { get { return _dict[key]; } set { _dict[key] = value; } }

            #endregion

            #region ICollection<KeyValuePair<T,K>> Members

            public void Add(KeyValuePair<T, K> item) { _dict.Add(item); _parent.ForcedUpdate(); }
            public void Clear() { _dict.Clear(); if (!_parent.Purging) _parent.ForcedUpdate(); }
            public bool Contains(KeyValuePair<T, K> item) { return _dict.Contains(item); }
            public void CopyTo(KeyValuePair<T, K>[] array, int arrayIndex) { _dict.CopyTo(array, arrayIndex); }
            public int Count { get { return _dict.Count; } }
            public bool IsReadOnly { get { return _dict.IsReadOnly; } }
            public bool Remove(KeyValuePair<T, K> item) { if (!_parent.Purging) _parent.ForcedUpdate(); return _dict.Remove(item); }

            #endregion

            #region IEnumerable<KeyValuePair<T,K>> Members

            public IEnumerator<KeyValuePair<T, K>> GetEnumerator() { return _dict.GetEnumerator(); }

            #endregion

            #region IEnumerable Members

            System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return _dict.GetEnumerator(); }

            #endregion
        }

        internal IList<Db4oTPChildEntity> DeletedChildren { get { return _deletedChildren; } }

        public virtual bool CheckConsistency() { return true; }

        private void DeleteChildren(Db4objects.Db4o.IObjectContainer container)
        {
            foreach (var child in _deletedChildren)
            {
                child.IsParentDeleted = true;
                container.Delete(child);
            }
            _deletedChildren.Clear();
        }

        private void ForcedUpdate() { _fake = 0; }

        #region IObjectCallbacks Members

        public virtual bool ObjectCanActivate(Db4objects.Db4o.IObjectContainer container) { return true; }
        public virtual bool ObjectCanDeactivate(Db4objects.Db4o.IObjectContainer container) { return true; }
        public virtual bool ObjectCanDelete(Db4objects.Db4o.IObjectContainer container) { return Purging; }
        public virtual bool ObjectCanNew(Db4objects.Db4o.IObjectContainer container) { return true; }
        public virtual bool ObjectCanUpdate(Db4objects.Db4o.IObjectContainer container) { return true; }

        public virtual void ObjectOnActivate(Db4objects.Db4o.IObjectContainer container) { }
        public virtual void ObjectOnDeactivate(Db4objects.Db4o.IObjectContainer container) { }
        public virtual void ObjectOnDelete(Db4objects.Db4o.IObjectContainer container) { DeleteChildren(container); }
        public virtual void ObjectOnNew(Db4objects.Db4o.IObjectContainer container) { }
        public virtual void ObjectOnUpdate(Db4objects.Db4o.IObjectContainer container) { DeleteChildren(container); }

        #endregion

        #region IDeletable Members

        public DateTime? DeletionTime { get { return _deletionTime; } }
        public bool IsDeleted { get { return _deleted; } }
        public virtual void Delete() { _deletionTime = DateTime.Now; _deleted = true; }
        public virtual void Undelete() { _deletionTime = null; _deleted = false; }

        #endregion
    }
}
